import fs from 'fs-extra'
import { join, basename, extname } from 'path'
import { fileURLToPath } from 'url'
import { format } from 'util'

function getPath(path) {
    return fileURLToPath(new URL(path, import.meta.url))
}

const threadPath = getPath('./template/thread.js')
const threadWorker = getPath('./template/thread.worker.js')

async function createWorker(source) {
    const _root = join(source, 'worker')
    const _threadPath = join(_root, 'thread.js')
    const _threadWorker = join(_root, 'thread.worker.js')
    const _threadWorkerTable = join(_root, 'thread.worker.table.js')
    const opts = {
        encoding: 'utf-8'
    }
    await fs.ensureDir(_root)
    await fs.copyFile(threadPath, _threadPath)
    await fs.copyFile(threadWorker, _threadWorker)
    const files = await fs.readdir(source)
    let modules = []
    for (const it of files) {
        if (it.endsWith('.worker.js')) {
            continue
        }
        if (it.endsWith('.js')) {
            const ext = extname(it)
            const name = basename(it, ext)
            modules.push(format('export * as %s from "../%s"', name, it))
            const s = join(source, it)
            const fileUrl = new URL('file:///' + s).href
            const module = await import(fileUrl)
            const te = [
                '/**',
                ' * 此文件由插件动态生成, 修改无效。',
                ' * 时间: ' + new Date().toLocaleString(),
                ' * 插件: vite-convert-worker',
                ' */',
                "import { run } from './worker/thread.js'\n"
            ]
            for (const prop in module) {
                const value = module[prop]
                if (typeof value === 'function') {
                    te.push(format('export async function %s(...args) {', prop))
                    te.push(
                        format(
                            "    return await run('%s', '%s', args.slice(0, %s), args.at(%s))",
                            name,
                            prop,
                            value.length,
                            value.length
                        )
                    )
                    te.push(format('}'))
                }
            }
            const path = join(source, name + '.worker.js')
            await fs.outputFile(path, te.join('\n'), opts)
            console.log(format('vite-convert-worker: 生成 %s', path))
        }
    }
    await fs.outputFile(_threadWorkerTable, modules.join('\n'), opts)
}

export function viteConvertWorker(source) {
    return {
        enforce: 'pre',
        name: 'vite-convert-worker',
        async buildStart(_options, _bundle) {
            return await createWorker(source)
        }
    }
}
